package com.buddy.java.thread.tow_phase_termination;

public abstract class AbstractTerminatableThread extends Thread implements Terminatable{

    public final TerminationToken terminationToken;

    public AbstractTerminatableThread(){
        this(new TerminationToken());
    }

    /**
     *
     * @param terminationToken
     *              线程间共享的线程终止标志
     */
    public AbstractTerminatableThread(TerminationToken terminationToken){
        super();
        this.terminationToken = terminationToken;
        terminationToken.register(this);
    }

    /**
     * 留给子类实现其线程的处理逻辑
     * @throws Exception
     */
    protected abstract void doRun() throws Exception;

    /**
     * 留给子类实现,用于实现线程停止后的一些清理动作
     * @param cause
     */
    protected void doCleanup(Exception cause){

    }

    /**
     * 留给子类实现,用于执行线程停止所需的操作
     */
    protected void doTerminate(){}

    @Override
    public void run() {
        //执行阶段,检查准备阶段所设置的线程停止标志和信号,决定停止线程的时机,并执行清理工作
        Exception ex = null;
        try {
            for (;;){
                if (terminationToken.isToShutdown()
                        && terminationToken.reservations.get() <=0){
                    break;
                }
                doRun();
            }
        } catch (Exception e) {
            ex = e;
        }finally {
            try{
                doCleanup(ex);
            }finally {
                terminationToken.notifyThreadTermination(this);
            }
        }
    }

    @Override
    public void interrupt() {
        terminate();
    }

    /**
     * 请求停止线程
     * 完成了线程停止的准备阶段
     */
    public void terminate() {
        terminationToken.setToShutdown(true);//指示目标线程可以停止
        try {
            doTerminate();
        }finally {
            //如果没有待处理任务,则强制终止线程
            if (terminationToken.reservations.get()<=0){
                super.interrupt();//
            }
        }
    }

    public void terminate(boolean waitUtilTHreadTerminated){
        terminate();
        if (waitUtilTHreadTerminated){
            try {
                this.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
